package com.fs.service;

import com.fs.entity.Customer;
import com.fs.repository.CustomerRepository;
import com.fs.service.bo.BoPageInfo;
import com.fs.service.bo.customer.BoCreateParam;
import com.fs.service.bo.customer.BoCustomer;
import com.fs.service.bo.customer.BoQueryParam;
import com.fs.utils.Utils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
@Validated
public class CustomerService {
    private final CustomerRepository customerDao;

    public CustomerService(CustomerRepository customerDao) {
        this.customerDao = customerDao;
    }

    public BoCustomer createCustomer(@Valid BoCreateParam param) {
        Customer customer = new Customer();
        customer.setPhone(param.getPhone());
        customer.setName(param.getName());
//        customer.setPhone(param.getPhone());
        customer.setWxID(param.getWxID());
        customer.setAvatarUrl(param.getAvatarUrl());
        customerDao.save(customer);
        return new BoCustomer(customer);
    }

    public BoPageInfo<BoCustomer> query(@NotNull BoQueryParam info, int pageNo, int pageSize) {
        Specification<Customer> spec = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.hasLength(info.getName())) {
                predicates.add(cb.like(root.get("name"), info.getName() + "%"));
            }
            if (info.getPhone() != null) {
                predicates.add(cb.equal(root.get("phone"), info.getPhone()));
            }
            int size = predicates.size();
            return query.where(predicates.toArray(new Predicate[size])).getRestriction();
        };

        if (pageNo > 0 && pageSize > 0) {
            Pageable pageable = PageRequest.of(--pageNo, pageSize, Sort.by(Sort.Direction.DESC, "id"));
            Page<Customer> page = customerDao.findAll(spec, pageable);
            List<BoCustomer> list = page.getContent().stream().map(BoCustomer::new).collect(Collectors.toList());
            return new BoPageInfo<>(list, page.getTotalElements());
        } else {
            List<Customer> customers = customerDao.findAll(spec);
            List<BoCustomer> list = customers.stream().map(BoCustomer::new).collect(Collectors.toList());
            return new BoPageInfo<>(list, (long) list.size());
        }
    }

    public BoCustomer findById(@NotNull Integer id) {
        Optional<Customer> opt = customerDao.findById(id);
        if (!opt.isPresent()) {
            throw new NotFoundException("没有找到客户");
        }
        return new BoCustomer(opt.get());
    }

    public BoCustomer findByOpenID(@NotNull String openID) {
        Customer customer = customerDao.findByWxID(openID);
        if (customer == null) {
            throw new NotFoundException("没有找到客户");
        }
        return new BoCustomer(customer);
    }

    public @Nullable
    BoCustomer findByOpenIDNotThrow(@NotNull String openID) {
        Customer customer = customerDao.findByWxID(openID);
        if (customer == null) {
            return null;
        }
        return new BoCustomer(customer);
    }

    public boolean existOpenID(@NotNull String openID) {
        return customerDao.existsByWxID(openID);
    }

    public int updateName(int id, @NotNull String name,@NotNull String avatar) {
        return customerDao.updateName(id, name,avatar);
    }

    public int updateToken(int id, @NotNull String token) {
        return customerDao.updateToken(id, token);
    }

}

